package com.meilai.project.service.media.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.meilai.project.dto.media.SaveMediaChooseDTO;
import com.meilai.project.dto.media.SaveMediaChooseDaterangeDTO;
import com.meilai.project.dto.media.UpdateMediaChooseDTO;
import com.meilai.project.entity.media.MediaPointChoose;
import com.meilai.project.entity.media.MediaPointChooseDaterange;
import com.meilai.project.entity.media.MediaPointChooseDaterangeMediapoint;
import com.meilai.project.exception.media.MediaChooseException;
import com.meilai.project.mapper.media.MediaPointChooseMapper;
import com.meilai.project.mapper.media.MediaPointOccupySnapshotMapper;
import com.meilai.project.service.media.MediaPointChooseDaterangeMediapointReplaceLogService;
import com.meilai.project.service.media.MediaPointChooseDaterangeMediapointService;
import com.meilai.project.service.media.MediaPointChooseDaterangeService;
import com.meilai.project.service.media.MediaPointChooseService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 选位集合，是选位资源的一个集合 服务实现类
 * </p>
 *
 * @author 张驰
 * @since 2022-01-25
 */
@Service
public class MediaPointChooseServiceImpl extends ServiceImpl<MediaPointChooseMapper, MediaPointChoose> implements MediaPointChooseService {

    private final DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private final DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private MediaPointChooseDaterangeService daterangeService;
    @Autowired
    private MediaPointChooseDaterangeMediapointService mediapointService;
    @Autowired
    private MediaPointChooseDaterangeMediapointReplaceLogService mediapointReplaceLogService;
    @Autowired
    private MediaPointOccupySnapshotMapper snapshotMapper;

    /**
     * 保存选位集合
     *
     * @param dto 入参对象
     * @throws MediaChooseException 选位保存异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveChoose(SaveMediaChooseDTO dto) throws MediaChooseException {
        validChooseDTO(dto);

        // 保存选位集合
        MediaPointChoose mpc = new MediaPointChoose();
        mpc.setType(dto.getType());
        save(mpc);

        // 更新从表
        updateSlave(mpc.getId(), dto.getDateranges());
    }

    /**
     * 更新选位
     *
     * @param dto 入参对象
     * @throws MediaChooseException 选位更新异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateChoose(UpdateMediaChooseDTO dto) throws MediaChooseException {
        if (dto.getId() == null) throw new MediaChooseException("选位集合id，不得为空");
        MediaPointChoose oldOne = getById(dto.getId());
        if (oldOne == null) throw new MediaChooseException("选位集合不存在");
        validChooseDTO(dto);

        // 保存选位集合
        MediaPointChoose mpc = new MediaPointChoose();
        mpc.setId(dto.getId());
        mpc.setType(dto.getType());
        updateById(mpc);

        // 更新从表
        updateSlave(dto.getId(), dto.getDateranges());
    }

//    /**
//     * 调位（替换点位）
//     * @param dto 入参对象
//     * @throws MediaChooseException 调位异常
//     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void replacePoints(ReplacePointsDTO dto) throws MediaChooseException {
//        if (dto.getChoose_id() == null) throw new MediaChooseException("选位集合id，不得为空");
//        if (dto.getDaterange_id() == null) throw new MediaChooseException("时间段id，不得为空");
//        if (CollectionUtils.isEmpty(dto.getPoints())) throw new MediaChooseException("需要替换的点位，不得为空");
//
//        Long userId = ThreadLocalUserUtil.get().getId();
//        LocalDateTime now = LocalDateTime.now();
//
//        List<Long> oldIds = new ArrayList<>();
//        List<MediaPointChooseDaterangeMediapointReplaceLog> oldPoints = new ArrayList<>();
//        List<MediaPointChooseDaterangeMediapoint> newPoints = new ArrayList<>();
//        for (ReplaceOnePointDTO rp : dto.getPoints()) {
//            Long oldId = rp.getOld_id();
//            Long newId = rp.getNew_id();
//            if (oldId == null) throw new MediaChooseException("存在替换前点位的id为空");
//            if (newId == null) throw new MediaChooseException("存在替换后点位的id为空");
//            oldIds.add(rp.getOld_id());
//            oldPoints.add(new MediaPointChooseDaterangeMediapointReplaceLog(dto.getChoose_id(), dto.getDaterange_id(), oldId, now));
//            newPoints.add(new MediaPointChooseDaterangeMediapoint(dto.getChoose_id(), dto.getDaterange_id(), newId));
//        }
//
//        LambdaQueryWrapper<MediaPointChooseDaterangeMediapoint> qw = Wrappers.<MediaPointChooseDaterangeMediapoint>lambdaQuery()
//                .eq(MediaPointChooseDaterangeMediapoint::getChoose_id, dto.getChoose_id()).eq(MediaPointChooseDaterangeMediapoint::getDaterange_id, dto.getDaterange_id())
//                .in(MediaPointChooseDaterangeMediapoint::getMedia_point_id, oldIds);
//        List<MediaPointChooseDaterangeMediapoint> curPoints = mediapointService.list(qw);
//        if(CollectionUtils.isEmpty(curPoints)) throw new MediaChooseException("替换前的点位为空");
//        if(curPoints.size() != oldIds.size()) throw new MediaChooseException("替换前的点位与提供的id数量不等");
//
//        // 删除原点位
//        mediapointService.remove(qw);
//        // 保存新点位
//        mediapointService.saveBatch(newPoints);
//        // 保存原点位历史
//        mediapointReplaceLogService.saveBatch(oldPoints);
//    }

    /**
     * 每天凌晨1点，为性能考虑，检查资源快照表，去除过期的时间段
     */
    @Override
    @Transactional
    @Scheduled(cron = "0 0 1 * * ?")
    public void scheduleRemoveSnapShot() {
        List<Long> expireIds = snapshotMapper.getExpireIds();
        if(CollectionUtils.isNotEmpty(expireIds)) snapshotMapper.deleteBatchIds(expireIds);
    }

    /**
     * 检验选位集合类型、时间段不为空
     */
    private void validChooseDTO(SaveMediaChooseDTO dto) throws MediaChooseException {
        if (dto.getType() == null) throw new MediaChooseException("选位集合类型，不得为空");
        if (dto.getType() <= 0 || dto.getType() >= 4)
            throw new MediaChooseException("选位集合类型必须为1~3，1:意向选位  2:合同  3:销售单（市场单、制作单、工单，共用）");
        if (CollectionUtils.isEmpty(dto.getDateranges())) throw new MediaChooseException("选位集合的时间段，不得为空");
    }

    /**
     * 更新从表
     */
    private void updateSlave(Long chooseId, List<SaveMediaChooseDaterangeDTO> ds) throws MediaChooseException {
        daterangeService.remove(Wrappers.<MediaPointChooseDaterange>lambdaQuery().eq(MediaPointChooseDaterange::getChoose_id, chooseId));
        mediapointService.remove(Wrappers.<MediaPointChooseDaterangeMediapoint>lambdaQuery().eq(MediaPointChooseDaterangeMediapoint::getChoose_id, chooseId));

        // 过滤有具体点位的时间段，进行保存
        boolean hasMediaPointId = false;
        List<SaveMediaChooseDaterangeDTO> dateranges = ds.stream().filter(d -> CollectionUtils.isNotEmpty(d.getMedia_point_ids())).collect(Collectors.toList());
        for (SaveMediaChooseDaterangeDTO d : dateranges) {
            if (!hasMediaPointId) hasMediaPointId = true;

            if (d.getStart_at() == null || d.getEnd_at() == null) throw new MediaChooseException("时间段存在空的起止时间");

            MediaPointChooseDaterange mpcd = new MediaPointChooseDaterange();
            mpcd.setChoose_id(chooseId);
            mpcd.setStart_at(getDateTime(d.getStart_at(), true));
            mpcd.setEnd_at(getDateTime(d.getEnd_at(), false));

            daterangeService.save(mpcd);

            List<MediaPointChooseDaterangeMediapoint> points = d.getMedia_point_ids().stream().distinct().map(id -> {
                MediaPointChooseDaterangeMediapoint mpcdmp = new MediaPointChooseDaterangeMediapoint();
                mpcdmp.setChoose_id(chooseId);
                mpcdmp.setDaterange_id(mpcd.getId());
                mpcdmp.setMedia_point_id(id);
                return mpcdmp;
            }).collect(Collectors.toList());

            mediapointService.saveBatch(points);
        }

        if (!hasMediaPointId) {
            // 没有具体点位
            throw new MediaChooseException("选位集合，没有点位ids");
        }
    }

    private LocalDateTime getDateTime(LocalDateTime time, boolean isStart) {
        return LocalDateTime.parse(time.format(dtf1) + (isStart ? " 00:00:00" : " 23:59:59"), dtf2);
    }
}
